/*
* Copyright 2003-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.attributes.compiler;
import java.util.ArrayList;
import java.util.List;
import org.apache.tools.ant.BuildException;
/**
* Parser for attribute expressions.
*/
public class AttributeExpressionParser {
public static class Argument {
public final String field;
public final String text;
public final int length;
public Argument (String field, String text, int length) {
this.field = field;
this.text = text;
this.length = length;
}
public boolean equalsOrNull (String a, String b) {
if (a == null) {
return b == null;
} else {
return b != null && a.equals (b);
}
}
public boolean equals (Object o) {
return o instanceof Argument &&
equalsOrNull (field, ((Argument) o).field) &&
((Argument) o).text.equals (text);
}
public String toString () {
return "[Argument: " + field + ", " + text + ", " + length + "]";
}
}
public static class ParseResult {
public final List arguments = new ArrayList ();
public final String className;
public ParseResult (String className) {
this.className = className;
}
public boolean equals (Object o) {
return o instanceof ParseResult &&
className.equals (((ParseResult) o).className) &&
arguments.equals (((ParseResult) o).arguments);
}
public String toString () {
return "[ParseResult: " + className + ", " + arguments + "]";
}
}
protected static Argument nextArgument (String string, int startPos, String filename, int line) {
if (string.charAt (startPos) == ')') {
return null;
}
StringBuffer sb = new StringBuffer ();
int i = startPos;
int depth = 0;
while (!( (string.charAt (i) == ',' || string.charAt (i) == ')') && depth == 0)) {
switch (string.charAt (i)) {
case '[':
case '{':
case '(': depth++; break;
case ']':
case '}':
case ')': depth--; break;
case '\'':
case '"': {
// handle string literals
char endChar = string.charAt (i);
sb.append (string.charAt (i));
i++;
while (true) {
char ch = string.charAt (i);
if (ch == '\\') {
sb.append (ch);
i++;
ch = string.charAt (i);
sb.append (ch);
} else {
if (ch == endChar) {
break;
}
sb.append (ch);
}
i++;
}
}
}
sb.append (string.charAt (i));
i++;
if (i == string.length ()) {
throw new BuildException (filename + ":" + line + ": Unterminated argument: " + string);
}
}
if (string.charAt (i) == ',') {
i++;
}
String text = sb.toString ();
String field = null;
int eqPos = text.indexOf ('=');
if (eqPos > -1) {
boolean identifier = true;
for (int j = 0; j < eqPos; j++) {
char ch = text.charAt (j);
if (Character.isJavaIdentifierPart (ch) || ch == ' ') {
} else {
identifier = false;
}
}
if (identifier) {
field = text.substring (0, eqPos).trim ();
text = text.substring (eqPos + 1).trim ();
}
}
Argument arg = new Argument (field, text, i - startPos);
return arg;
}
public static ParseResult parse (String string, String filename, int line) {
StringBuffer sb = new StringBuffer ();
int i = 0;
while (i < string.length () && (Character.isJavaIdentifierPart (string.charAt (i)) || string.charAt (i) == '.' || string.charAt (i) == ' ')) {
sb.append (string.charAt (i));
i++;
}
if (i == string.length () || string.charAt (i) != '(') {
throw new BuildException (filename + ":" + line + ": Illegal expression: " + string);
}
ParseResult result = new ParseResult (sb.toString ());
i++;
Argument arg = null;
boolean seenField = false;
while ((arg = nextArgument (string, i, filename, line)) != null) {
if (arg.field != null) {
seenField = true;
}
if (seenField && arg.field == null) {
throw new BuildException (filename + ":" + line + ": Un-named parameters must come before the named parameters: " + string);
}
result.arguments.add (arg);
i += arg.length;
}
return result;
}
}